{% extends 'base.html' %}

{% block extra_css %}
<style>
    #graphView {
        width: 100%;
        height: 800px;
        background: #1a1a1a;
    }
    
    #device-panel {
        position: absolute;
        left: 20px;
        top: 20px;
        background: rgba(0, 10, 20, 0.85);
        color: #fff;
        padding: 15px;
        border-radius: 8px;
        width: 280px;
        z-index: 100;
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
        backdrop-filter: blur(5px);
        display: none;
    }
    
    .status-indicator {
        display: inline-block;
        width: 10px;
        height: 10px;
        border-radius: 50%;
        margin-right: 5px;
    }
    
    .status-up {
        background-color: #00ff00;
    }
    
    .status-down {
        background-color: #ff0000;
    }
    
    .device-label {
        position: absolute;
        padding: 2px 5px;
        background: rgba(0,0,0,0.7);
        color: white;
        border-radius: 3px;
        font-size: 12px;
        pointer-events: none;
        white-space: nowrap;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid p-0">
    <div id="graphView"></div>
    <div id="device-panel">
        <h5><i class="fas fa-server mr-2"></i>设备信息</h5>
        <div id="device-info">
            <div class="mb-2">
                <span class="text-muted">名称：</span>
                <span id="device-name"></span>
            </div>
            <div class="mb-2">
                <span class="text-muted">类型：</span>
                <span id="device-type"></span>
            </div>
            <div class="mb-2">
                <span class="text-muted">IP：</span>
                <span id="device-ip"></span>
            </div>
            <div class="mb-2">
                <span class="text-muted">状态：</span>
                <span id="device-status"></span>
            </div>
            <div class="mb-2">
                <span class="text-muted">连接：</span>
                <div id="device-connections"></div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function() {
    // 获取容器元素
    const container = document.getElementById('graphView');
    if (!container) {
        console.error('找不到 graphView 容器');
        return;
    }
    
    // 初始化场景
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x1a1a1a);  // 设置场景背景色
    
    // 设置相机
    const camera = new THREE.PerspectiveCamera(
        75,
        container.offsetWidth / container.offsetHeight,
        0.1,
        1000
    );
    camera.position.set(15, 15, 15);  // 调整相机位置
    
    // 设置渲染器
    const renderer = new THREE.WebGLRenderer({ 
        antialias: true,
        alpha: true
    });
    renderer.setSize(container.offsetWidth, container.offsetHeight);
    renderer.setPixelRatio(window.devicePixelRatio);  // 设置像素比
    container.appendChild(renderer.domElement);
    
    // 添加光源
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(ambientLight);
    
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(10, 10, 10);
    scene.add(directionalLight);
    
    // 添加点光源
    const pointLight = new THREE.PointLight(0xffffff, 0.5);
    pointLight.position.set(0, 10, 0);
    scene.add(pointLight);
    
    // 控制器
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.minDistance = 5;
    controls.maxDistance = 50;
    
    // 添加网格地面（可选）
    const gridHelper = new THREE.GridHelper(50, 50, 0x444444, 0x222222);
    scene.add(gridHelper);
    
    // 将拓扑数据作为JavaScript对象直接嵌入
    const topology = {
        nodes: [
            {% for device in devices %}
            {
                id: {{ device.id }},
                name: '{{ device.name|escapejs }}',
                type: '{{ device.device_type }}',
                ip: '{{ device.ip_address|default:"" }}',
                x: {{ device.position_x }},
                y: {{ device.position_y }},
                z: {{ device.position_z }},
                status: {{ device.status|yesno:"true,false" }}
            }{% if not forloop.last %},{% endif %}
            {% endfor %}
        ],
        links: [
            {% for conn in connections %}
            {
                source: {{ conn.source_id }},
                target: {{ conn.target_id }},
                type: '{{ conn.link_type }}',
                status: {{ conn.status|yesno:"true,false" }}
            }{% if not forloop.last %},{% endif %}
            {% endfor %}
        ]
    };
    
    // 设备类型配置
    const deviceConfig = {
        router: {
            color: 0xff0000,
            scale: 1.2
        },
        switch: {
            color: 0x00ff00,
            scale: 1
        },
        firewall: {
            color: 0x0000ff,
            scale: 1.1
        },
        server: {
            color: 0xffff00,
            scale: 1
        }
    };
    
    // 存储设备对象
    const deviceObjects = new Map();
    
    // 创建设备
    topology.nodes.forEach(node => {
        const config = deviceConfig[node.type] || deviceConfig.server;  // 添加默认配置
        const geometry = new THREE.BoxGeometry(1, 1, 1);
        const material = new THREE.MeshPhongMaterial({
            color: config.color,
            metalness: 0.7,
            roughness: 0.3,
            emissive: node.status ? 0x222222 : 0,
            emissiveIntensity: 0.2
        });
        
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.set(
            node.x || 0,  // 添加默认值
            node.y || 0,
            node.z || 0
        );
        mesh.scale.setScalar(config.scale || 1);
        mesh.userData = node;
        
        // 添加设备标签
        const labelDiv = document.createElement('div');
        labelDiv.className = 'device-label';
        labelDiv.textContent = node.name;
        labelDiv.style.color = '#ffffff';
        labelDiv.style.padding = '2px 5px';
        labelDiv.style.background = 'rgba(0,0,0,0.7)';
        labelDiv.style.borderRadius = '3px';
        
        scene.add(mesh);
        deviceObjects.set(node.id, mesh);
    });
    
    // 创建连接线
    topology.links.forEach(link => {
        const sourceDevice = deviceObjects.get(link.source);
        const targetDevice = deviceObjects.get(link.target);
        
        if (sourceDevice && targetDevice) {
            const points = [
                sourceDevice.position.clone(),
                targetDevice.position.clone()
            ];
            
            const geometry = new THREE.BufferGeometry().setFromPoints(points);
            const material = new THREE.LineBasicMaterial({
                color: link.type === 'fiber' ? 0x00ff00 : 0xff9900,
                linewidth: 2,
                opacity: link.status ? 1 : 0.3,
                transparent: true
            });
            
            const line = new THREE.Line(geometry, material);
            line.userData = link;
            scene.add(line);
        }
    });
    
    // 射线检测器
    const raycaster = new THREE.Raycaster();
    const mouse = new THREE.Vector2();
    
    // 鼠标移动事件
    function onMouseMove(event) {
        const rect = renderer.domElement.getBoundingClientRect();
        mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
        
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(scene.children);
        
        if (intersects.length > 0) {
            const object = intersects[0].object;
            if (object.userData && object.userData.type) {
                document.body.style.cursor = 'pointer';
                return;
            }
        }
        
        document.body.style.cursor = 'default';
    }
    
    // 鼠标点击事件
    function onMouseClick(event) {
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(scene.children);
        
        if (intersects.length > 0) {
            const object = intersects[0].object;
            if (object.userData && object.userData.type) {
                showDeviceInfo(object.userData);
            }
        } else {
            document.getElementById('device-panel').style.display = 'none';
        }
    }
    
    // 显示设备信息
    function showDeviceInfo(device) {
        document.getElementById('device-name').textContent = device.name;
        document.getElementById('device-type').textContent = getDeviceTypeName(device.type);
        document.getElementById('device-ip').textContent = device.ip || 'N/A';
        
        const statusHtml = `
            <span class="status-indicator ${device.status ? 'status-up' : 'status-down'}"></span>
            ${device.status ? '正常' : '故障'}
        `;
        document.getElementById('device-status').innerHTML = statusHtml;
        
        // 显示连接信息
        const connections = topology.links.filter(
            link => link.source === device.id || link.target === device.id
        );
        
        const connectionsHtml = connections.map(conn => {
            const otherDevice = topology.nodes.find(n => 
                n.id === (conn.source === device.id ? conn.target : conn.source)
            );
            return `
                <div class="ml-3 mb-1">
                    <span class="status-indicator ${conn.status ? 'status-up' : 'status-down'}"></span>
                    ${otherDevice.name} (${conn.type === 'fiber' ? '光纤' : '网线'})
                </div>
            `;
        }).join('');
        
        document.getElementById('device-connections').innerHTML = connectionsHtml;
        document.getElementById('device-panel').style.display = 'block';
    }
    
    // 获取设备类型名称
    function getDeviceTypeName(type) {
        const types = {
            router: '路由器',
            switch: '交换机',
            firewall: '防火墙',
            server: '服务器'
        };
        return types[type] || type;
    }
    
    // 添加事件监听
    renderer.domElement.addEventListener('mousemove', onMouseMove);
    renderer.domElement.addEventListener('click', onMouseClick);
    
    // 窗口大小调整
    window.addEventListener('resize', function() {
        if (!container) return;
        
        camera.aspect = container.offsetWidth / container.offsetHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(container.offsetWidth, container.offsetHeight);
    });
    
    // 动画循环
    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }
    
    animate();
});
</script>
{% endblock %} 